Imports Microsoft.VisualBasic
Imports System
Imports System.Speech.Synthesis
Imports System.Speech.Recognition
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Windows.Forms
Imports System.IO

Namespace C4F.DevKit.Speech

	''' <summary>
	''' Speech API's main class.
	''' </summary>
	Public Class SapiManager
		Inherits System.ComponentModel.Component

		#Region "Globals"

		''' <summary>
		''' Global variables required.
		''' </summary>
        Private WithEvents speechSynthesizer As SpeechSynthesizer
        Private WithEvents recognizerEngine As SpeechRecognitionEngine
        Private WithEvents dictationRecognizerEngine As SpeechRecognitionEngine
		Private customGrammar As Grammar
		Private dictationGrammar As DictationGrammar
		Private currentPrompt As Prompt
        Private voicesList As List(Of VoiceInfo)

        Private DEFAULT_SPEECH_RATE As Integer = 2
        Private DEFAULT_SPEECH_VOLUME As Integer = 50
        Private Const WAV_EXTENSION As String = "wav"

#End Region

        ''' <summary>
        ''' Returns a list of voices that can be used.
        ''' </summary>
        Public ReadOnly Property Voices() As List(Of VoiceInfo)
            Get
                If voicesList Is Nothing Then
                    Return voicesList
                Else
                    Return New List(Of VoiceInfo)()
                End If
            End Get
        End Property

        ''' <summary>
        ''' Current voice being used. If you'd like to change the selected voice, use the SelectVoice method.
        ''' </summary>
        Public ReadOnly Property CurrentVoice() As VoiceInfo
            Get
                Dim voiceId As String = speechSynthesizer.Voice.Id
                Dim voiceInfo As VoiceInfo = New VoiceInfo()

                If Not Voices Is Nothing Then
                    For Each voice As VoiceInfo In Voices
                        If voice.VoiceId = voiceId Then
                            voiceInfo = voice
                            Exit For
                        End If
                    Next voice
                End If

                Return voiceInfo
            End Get
        End Property

#Region "Methods"

        ''' <summary>
        ''' Constructor for SAPI class.
        ''' </summary>
        Public Sub New()
            ' Intialize speechSynthesizer object.
            speechSynthesizer = New SpeechSynthesizer()
            AddHandler StateChanged, AddressOf SapiManager_StateChanged
            AddHandler SpeechRecognized, AddressOf SapiManager_SpeechRecognized

            Me.speechSynthesizer.Volume = Me.DEFAULT_SPEECH_VOLUME
            Me.speechSynthesizer.Rate = Me.DEFAULT_SPEECH_RATE

            Try
                voicesList = Me.GetAllInstalledVoices()
            Catch
                voicesList = Nothing
            End Try

            Try
                If voicesList.Count > 0 AndAlso (Not String.IsNullOrEmpty(voicesList(0).Name)) Then
                    Me.SelectVoice(voicesList(0).Name) ' use the first voice by default
                End If
            Catch
                ' Do nothing
            End Try
        End Sub

        ''' <summary>
        ''' Iternal purpose. 
        ''' </summary>
        ''' <param name="text"></param>
        Private Sub SapiManager_SpeechRecognized(ByVal text As String)
        End Sub

        ''' <summary>
        ''' Iternal purpose.
        ''' </summary>
        Private Sub SapiManager_StateChanged()
        End Sub

#Region "Events and delegates"

        ''' <summary>
        ''' Custom event handler for speech-recognition event.  
        ''' </summary>
        ''' <param name="text">Returns speech text recognized.</param>
        Public Delegate Sub SapiSpeechRecognizedEventHandler(ByVal text As String)

        ''' <summary>
        ''' Event occurs whenever recognition system recognizes speech.
        ''' </summary>
        Public Event SpeechRecognized As SapiSpeechRecognizedEventHandler

        ''' <summary>
        ''' Custom event handler for speech-state change event.
        ''' </summary>
        Public Delegate Sub SapiStateChnageEventHandler()

        ''' <summary>
        ''' Event occurs whenever speech engine's state changes.
        ''' </summary>
        Public Event StateChanged As SapiStateChnageEventHandler

#End Region

#Region "Synthesizer related methods"

        Private Sub SpeechSynthesizerStateChanged(ByVal sender As Object, ByVal e As System.Speech.Synthesis.StateChangedEventArgs) Handles speechSynthesizer.StateChanged
            RaiseEvent StateChanged()
        End Sub

        ''' <summary>
        ''' Lists all the voices installed on the machine.
        ''' </summary>
        ''' <returns>List of structure of voiceinfo installed on the machine.</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' collecting information about voices installed.</exception>
        Public Function GetAllInstalledVoices() As List(Of VoiceInfo)
            Try
                Dim installedVoices As List(Of VoiceInfo) = New List(Of VoiceInfo)()
                Dim voices_Renamed As System.Collections.ObjectModel.ReadOnlyCollection(Of InstalledVoice) = speechSynthesizer.GetInstalledVoices(CultureInfo.CurrentCulture)
                For Each voice As InstalledVoice In voices_Renamed
                    installedVoices.Add(ToLocalVoiceInfo(voice))
                Next voice
                Return installedVoices
            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try
        End Function

        Private Function ToLocalVoiceInfo(ByVal voice As InstalledVoice) As VoiceInfo
            Dim voiceInfo As VoiceInfo = New VoiceInfo()
            voiceInfo.Age = CType(voice.VoiceInfo.Age, VoiceAge)
            voiceInfo.Description = voice.VoiceInfo.Description
            voiceInfo.Gender = CType(voice.VoiceInfo.Gender, VoiceGender)
            voiceInfo.VoiceId = voice.VoiceInfo.Id
            voiceInfo.Name = voice.VoiceInfo.Name

            Return voiceInfo
        End Function

        ''' <summary>
        ''' Voice rate.
        ''' </summary>        
        Public Property VoiceRate() As Integer

            Get
                Return speechSynthesizer.Rate
            End Get

            Set(ByVal value As Integer)
                speechSynthesizer.Rate = value
            End Set

        End Property

        ''' <summary>
        ''' Voice volume.
        ''' </summary>
        Public Property VoiceVolume() As Integer

            Get
                Return speechSynthesizer.Volume
            End Get

            Set(ByVal value As Integer)
                speechSynthesizer.Volume = value
            End Set

        End Property

        ''' <summary>
        ''' Sapi state.
        ''' </summary>
        Public ReadOnly Property State() As SynthesizerState

            Get
                Return CType(speechSynthesizer.State, SynthesizerState)
            End Get

        End Property

        ''' <summary>
        ''' Sets the voice for speaking.
        ''' </summary>
        ''' <param name="personName">Voice name to set.</param>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' setting voice to read fails.</exception>
        Public Sub SelectVoice(ByVal personName As String)
            Try
                speechSynthesizer.SelectVoice(personName)

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Sets the voice for speaking.
        ''' </summary>
        ''' <param name="personGender">Gender name to setting voice.</param>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' setting voice to read fails.</exception>
        Public Sub SelectVoice(ByVal personGender As VoiceGender)

            Try
                speechSynthesizer.SelectVoiceByHints(CType(personGender, System.Speech.Synthesis.VoiceGender))

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Sets the voice for speaking.
        ''' </summary>
        ''' <param name="personGender">Gender of voice.</param>
        ''' <param name="personAge">Age of voice</param>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' setting voice to read fails.</exception>
        Public Sub SelectVoice(ByVal personGender As VoiceGender, ByVal personAge As VoiceAge)
            Try
                speechSynthesizer.SelectVoiceByHints(CType(personGender, System.Speech.Synthesis.VoiceGender), CType(personAge, System.Speech.Synthesis.VoiceAge))
            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try
        End Sub

        ''' <summary>
        ''' Speaks the given text provided.
        ''' </summary>
        ''' <param name="textToSpeak">Text to speak.</param>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' speaking text fails.</exception>
        Public Sub Speak(ByVal textToSpeak As String)
            Try
                speechSynthesizer.SetOutputToDefaultAudioDevice()
                currentPrompt = speechSynthesizer.SpeakAsync(textToSpeak)
            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try
        End Sub

        ''' <summary>
        ''' Speaks the text from the specified file.
        ''' </summary>
        ''' <param name="fileName">The file path/name to read text from. If string.Empty, the user will be prompted with a OpenDialog.</param>
        Public Sub SpeakFile(ByVal fileName As String)
            SpeakFile(GetTextFromFile(fileName))
        End Sub

        ''' <summary>
        ''' Speaks the text from a file. Prompts the user with a OpenDialog.
        ''' </summary>
        Public Sub SpeakFile()
            SpeakFile(GetTextFromFile())
        End Sub

        ''' <summary>
        ''' Speaks the given text provided.
        ''' </summary>
        ''' <param name="textToSpeak">Text in SSML format.</param>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' speaking text fails.</exception>
        Public Sub SpeakSsml(ByVal textToSpeak As String)

            Try
                speechSynthesizer.SetOutputToDefaultAudioDevice()
                currentPrompt = speechSynthesizer.SpeakSsmlAsync(textToSpeak)

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Speaks the given text provided and stores it in the form of .wav file.
        ''' </summary>
        ''' <param name="textToSpeak">Text to speak.</param>
        ''' <param name="SsmlText">Keep it true if you are passing SSML text.</param>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' coverting text to wave file fails.</exception>
        Public Sub ToWave(ByVal textToSpeak As String, ByVal SsmlText As Boolean)
            ToWave(textToSpeak, String.Empty, SsmlText)
        End Sub

        ''' <summary>
        ''' Speaks the given text provided and stores it in the form of .wav file.
        ''' </summary>
        ''' <param name="textToSpeak">Text to speak.</param>
        ''' <param name="fileName">.Wav file name.</param>
        ''' <param name="SsmlText">Keep it true if you are passing SSML text.</param>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' coverting text to wave file fails.</exception>
        Public Sub ToWave(ByVal textToSpeak As String, ByVal fileName As String, ByVal SsmlText As Boolean)
            Try
                If fileName = String.Empty Then
                    Dim sfd As SaveFileDialog = New SaveFileDialog()
                    sfd.Filter = String.Format("All files (*.*)|*.*|{0} files (*.{0})|*.{0}", WAV_EXTENSION)
                    sfd.Title = "Save to a wave file"
                    sfd.FilterIndex = 2
                    sfd.RestoreDirectory = True

                    If sfd.ShowDialog() = System.Windows.Forms.DialogResult.OK AndAlso (Not String.IsNullOrEmpty(sfd.FileName)) Then
                        fileName = sfd.FileName
                    End If
                End If

                If (Not String.IsNullOrEmpty(fileName)) Then
                    speechSynthesizer.SetOutputToWaveFile(fileName)
                    If SsmlText = False Then
                        speechSynthesizer.SpeakAsync(textToSpeak)
                    Else
                        speechSynthesizer.SpeakSsmlAsync(textToSpeak)
                    End If
                End If
            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try
        End Sub

        ''' <summary>
        ''' Speaks the given text provided and generates stream out of it.
        ''' </summary>
        ''' <param name="textToSpeak">Text to speak.</param>
        ''' <param name="SsmlText">Keep it true if you are passing SSML text.</param>
        ''' <returns>Stream</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' converting text to stream fails.</exception>
        Public Function ToStream(ByVal textToSpeak As String, ByVal SsmlText As Boolean) As System.IO.Stream

            Try

                Dim tempStream As System.IO.MemoryStream = New System.IO.MemoryStream()
                speechSynthesizer.SetOutputToWaveStream(tempStream)

                If SsmlText = False Then
                    speechSynthesizer.Speak(textToSpeak)
                Else
                    speechSynthesizer.SpeakSsml(textToSpeak)
                End If

                speechSynthesizer.SetOutputToDefaultAudioDevice()

                Return tempStream


            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Function

        ''' <summary>
        ''' Pauses speaking.
        ''' </summary>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' pausing speech synthesizer engine fails.</exception>
        Public Sub PauseSpeaking()

            Try
                speechSynthesizer.Pause()

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Resumes speaking.
        ''' </summary>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' resuming speech synthesizer engine fails.</exception>
        Public Sub ResumeSpeaking()

            Try
                speechSynthesizer.Resume()

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Stops speaking.
        ''' </summary>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' stopping speech synthesizer engine fails.</exception>
        Public Sub StopSpeaking()

            Try
                speechSynthesizer.SpeakAsyncCancel(currentPrompt)
            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try
        End Sub

        ''' <summary>
        ''' Retrieves the text from the specified file. User will be prompted with an open dialog.
        ''' </summary>
        ''' <param name="fileName">The file path/name to retrieve text from. If string.empty, the user will be prompted with an OpenDialog.</param>
        ''' <returns>The text of the file.</returns>
        Public Function GetTextFromFile(ByVal fileName As String) As String
            If String.IsNullOrEmpty(fileName) Then
                Dim dlg As OpenFileDialog = New OpenFileDialog()

                If dlg.ShowDialog() = System.Windows.Forms.DialogResult.OK AndAlso (Not String.IsNullOrEmpty(dlg.FileName)) Then
                    Dim filePath As String = dlg.FileName
                    Dim theFile As StreamReader = File.OpenText(filePath)

                    fileName = theFile.ReadToEnd()
                End If
            End If

            If (Not fileName Is Nothing) Then
                Return fileName
            Else
                Return String.Empty
            End If
        End Function

        ''' <summary>
        ''' Retrieves the text from a file. User will be prompted with an OpenDialog.
        ''' </summary>
        ''' <returns>The text from the file.</returns>
        Public Function GetTextFromFile() As String
            Return GetTextFromFile(String.Empty)
        End Function

#End Region

#Region "Recognition related methods"

        ''' <summary>
        ''' Gives the list of recognizers available on the machine.
        ''' </summary>
        ''' <returns>List of structure of recognizers.</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' collecting information about installed recognizers fails.</exception>
        Public Shared Function GetInstalledRecognizers() As List(Of RecognizerInfo)
            Try
                Dim installedRecognizers As List(Of RecognizerInfo) = New List(Of RecognizerInfo)()
                Dim recognizers As System.Collections.ObjectModel.ReadOnlyCollection(Of System.Speech.Recognition.RecognizerInfo) = SpeechRecognitionEngine.InstalledRecognizers()
                For Each recognizer As System.Speech.Recognition.RecognizerInfo In recognizers
                    Dim recognizerInfo As RecognizerInfo = New RecognizerInfo()
                    recognizerInfo.Description = recognizer.Description
                    recognizerInfo.RecognizerId = recognizer.Id
                    recognizerInfo.Name = recognizer.Name
                    installedRecognizers.Add(recognizerInfo)
                Next recognizer

                Return installedRecognizers


            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Function

        ''' <summary>
        ''' Initializes Dictation engine.
        ''' </summary>
        ''' <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        ''' <returns>Returns true if succeeded.</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' initializing Dictation engine fails.</exception>
        Public Function InitializeDictationEngine(ByVal recognizerId As String) As Boolean
            Try

                If (Not String.IsNullOrEmpty(recognizerId)) Then
                    dictationRecognizerEngine = New SpeechRecognitionEngine(recognizerId)
                Else
                    dictationRecognizerEngine = New SpeechRecognitionEngine(CultureInfo.CurrentCulture)
                End If

                dictationRecognizerEngine.SetInputToDefaultAudioDevice()
                dictationGrammar = New DictationGrammar()
                dictationRecognizerEngine.UnloadAllGrammars()
                dictationRecognizerEngine.LoadGrammar(dictationGrammar)

                Return True


            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Function

        ''' <summary>
        ''' Initializes Dictation engine.
        ''' </summary>
        ''' <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        ''' <param name="streamToRecognize">Stream of data.</param>
        ''' <returns>Returns true if succeeded.</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' initializing Dictation engine fails.</exception>
        Public Function InitializeDictationEngine(ByVal recognizerId As String, ByVal streamToRecognize As System.IO.Stream) As Boolean
            Try
                If (Not String.IsNullOrEmpty(recognizerId)) Then
                    dictationRecognizerEngine = New SpeechRecognitionEngine(recognizerId)
                Else
                    dictationRecognizerEngine = New SpeechRecognitionEngine(CultureInfo.CurrentCulture)
                End If
                dictationRecognizerEngine.SetInputToWaveStream(streamToRecognize)
                dictationGrammar = New DictationGrammar()
                dictationRecognizerEngine.UnloadAllGrammars()
                dictationRecognizerEngine.LoadGrammar(dictationGrammar)
                Return True
            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try
        End Function

        ''' <summary>
        ''' Initializes Dictation engine.
        ''' </summary>
        ''' <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        ''' <param name="filePath">.Wav file for recognize</param>
        ''' <returns>Returns true if succeeded.</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' initializing Dictation engine fails.</exception>
        Public Function InitializeDictationEngine(ByVal recognizerId As String, ByVal filePath As String) As Boolean

            Try
                If (Not String.IsNullOrEmpty(recognizerId)) Then
                    dictationRecognizerEngine = New SpeechRecognitionEngine(recognizerId)
                Else
                    dictationRecognizerEngine = New SpeechRecognitionEngine(CultureInfo.CurrentCulture)
                End If

                dictationRecognizerEngine.SetInputToWaveFile(filePath)
                dictationGrammar = New DictationGrammar()
                dictationRecognizerEngine.UnloadAllGrammars()
                dictationRecognizerEngine.LoadGrammar(dictationGrammar)

                Return True

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Function

        ''' <summary>
        ''' Initializes Speech Recognition engine.
        ''' </summary>
        ''' <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        ''' <param name="words">Array of words for grammar.</param>
        ''' <returns>Returns true if succeeded.</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' initializing Speech Recognition engine fails.</exception>
        Public Function InitializeSpeechRecognitionEngine(ByVal recognizerId As String, ByVal words As String()) As Boolean

            Try

                If (Not String.IsNullOrEmpty(recognizerId)) Then
                    recognizerEngine = New SpeechRecognitionEngine(recognizerId)
                Else
                    recognizerEngine = New SpeechRecognitionEngine(CultureInfo.CurrentCulture)
                End If

                recognizerEngine.SetInputToDefaultAudioDevice()
                customGrammar = CreateCustomGrammar(words)
                recognizerEngine.UnloadAllGrammars()

                If Not customGrammar Is Nothing Then
                    recognizerEngine.LoadGrammar(customGrammar)
                End If

                Return True


            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Function

        ''' <summary>
        ''' Initializes Speech Recognition engine.
        ''' </summary>
        ''' <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        ''' <param name="words">Array of words for grammar.</param>
        ''' <param name="stream">Stream of data to recognize.</param>
        ''' <returns>Returns true if succeeded.</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' initializing Speech Recognition engine fails.</exception>
        Public Function InitializeSpeechRecognitionEngine(ByVal recognizerId As String, ByVal words As String(), ByVal stream As System.IO.Stream) As Boolean

            Try
                If (Not String.IsNullOrEmpty(recognizerId)) Then
                    recognizerEngine = New SpeechRecognitionEngine(recognizerId)
                Else
                    recognizerEngine = New SpeechRecognitionEngine(CultureInfo.CurrentCulture)
                End If

                recognizerEngine.SetInputToAudioStream(stream, Nothing)
                customGrammar = CreateCustomGrammar(words)
                recognizerEngine.UnloadAllGrammars()

                If Not customGrammar Is Nothing Then
                    recognizerEngine.LoadGrammar(customGrammar)
                End If

                Return True


            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Function

        ''' <summary>
        ''' Initializes Speech Recognition engine.
        ''' </summary>
        ''' <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        ''' <param name="words">Array of words for grammar.</param>
        ''' <param name="filePath">.Wav file for recognize</param>
        ''' <returns>Returns true if succeeded.</returns>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' initializing Speech Recognition engine fails.</exception>
        Public Function InitializeSpeechRecognitionEngine(ByVal recognizerId As String, ByVal words As String(), ByVal filePath As String) As Boolean

            Try

                If (Not String.IsNullOrEmpty(recognizerId)) Then
                    recognizerEngine = New SpeechRecognitionEngine(recognizerId)
                Else
                    recognizerEngine = New SpeechRecognitionEngine(CultureInfo.CurrentCulture)
                End If

                recognizerEngine.SetInputToWaveFile(filePath)
                customGrammar = CreateCustomGrammar(words)
                recognizerEngine.UnloadAllGrammars()

                If Not customGrammar Is Nothing Then
                    recognizerEngine.LoadGrammar(customGrammar)
                End If

                Return True


            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Function

        Private Sub RecognizerEngineRecognizeCompleted(ByVal sender As Object, ByVal e As RecognizeCompletedEventArgs) Handles recognizerEngine.RecognizeCompleted

            Try
                recognizerEngine.SetInputToDefaultAudioDevice()
            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        Private Sub RecognizerEngineSpeechRecognized(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs) Handles recognizerEngine.SpeechRecognized
            RaiseEvent SpeechRecognized(e.Result.Text)
        End Sub

        Private Sub DictationRecognizerEngine_RecognizeCompleted(ByVal sender As Object, ByVal e As RecognizeCompletedEventArgs) Handles dictationRecognizerEngine.RecognizeCompleted

            Try
                dictationRecognizerEngine.SetInputToDefaultAudioDevice()
            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        Private Sub DictationRecognizerEngine_SpeechRecognized(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs) Handles dictationRecognizerEngine.SpeechRecognized
            RaiseEvent SpeechRecognized(e.Result.Text)
        End Sub

        ''' <summary>
        ''' Starts Speech Recognition engine.
        ''' </summary>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' starting Speech Recognition engine fails.</exception>
        Public Sub StartSpeechRecognitionEngine()

            Try
                recognizerEngine.RecognizeAsync(RecognizeMode.Multiple)

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Starts Dictation engine.
        ''' </summary>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' starting Dictation engine fails.</exception>
        Public Sub StartDictationEngine()

            Try
                dictationRecognizerEngine.RecognizeAsync(RecognizeMode.Multiple)

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Stops the Speech Recognition engine.
        ''' </summary>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' stopping Speech Recognition engine fails.</exception>
        Public Sub StopSpeechRecognitionEngine()

            Try
                If Not recognizerEngine Is Nothing Then
                    recognizerEngine.RecognizeAsyncCancel()
                End If

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Stops the Dictation engine.
        ''' </summary>
        ''' <exception cref="SapiManagerException">Thrown when 
        ''' stopping Dictation engine fails.</exception>
        Public Sub StopDictationEngine()

            Try
                If Not dictationRecognizerEngine Is Nothing Then
                    dictationRecognizerEngine.RecognizeAsyncCancel()
                End If

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Sub

        ''' <summary>
        ''' Creates grammar for given words.
        ''' </summary>
        ''' <param name="words">Array of words for grammar.</param>
        ''' <returns>Custom grammar for given words.</returns>
        Private Function CreateCustomGrammar(ByVal words As String()) As Grammar

            Try
                Dim grammarBuilder As GrammarBuilder = New GrammarBuilder()
                grammarBuilder.Append(New Choices(words))
                Return New Grammar(grammarBuilder)

            Catch exception As Exception
                Throw New SapiManagerException(exception.Message, exception)
            End Try

        End Function

#End Region

#End Region

	End Class

End Namespace